﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;

namespace DataService.CrudClassGenerator
{
    //#pragma warning disable 1591
    /// <summary>
    /// Used to Batch Processes
    /// </summary>
    public class CCGBatchProcess
    {
        #region [CONSTRUCTORS] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <returns></returns>
        public static CCGBatchProcess Instance()
        {
            return new CCGBatchProcess();
        }
        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <param name="pDatabaseName">Database name to be acted on. 
        /// If this parameter is not given, default database is used. 
        /// Default database name is written in config file as the name of "DefaultDBName"</param>
        /// <returns></returns>
        public static CCGBatchProcess Instance(string pDatabaseName)
        {
            return new CCGBatchProcess(pDatabaseName);
        }
        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <param name="pChangeParameterNames">If this parameter value is given as true, the name of all parameters will be changed</param>
        /// <returns></returns>
        public static CCGBatchProcess Instance(bool pChangeParameterNames)
        {
            return new CCGBatchProcess(pChangeParameterNames);
        }
        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <param name="pDatabaseName">Database name to be acted on. 
        /// If this parameter is not given, default database is used. 
        /// Default database name is written in config file as the name of "DefaultDBName</param>
        /// <param name="pChangeParameterNames">If this parameter value is given as true, the name of all parameters will be changed</param>
        /// <returns></returns>
        public static CCGBatchProcess Instance(string pDatabaseName, bool pChangeParameterNames)
        {
            return new CCGBatchProcess(pDatabaseName, pChangeParameterNames);
        }

        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <returns></returns>
        public CCGBatchProcess()
        {
        }
        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <param name="pDatabaseName">Database name to be acted on. 
        /// If this parameter is not given, default database is used. 
        /// Default database name is written in config file as the name of "DefaultDBName"</param>
        /// <returns></returns>
        public CCGBatchProcess(string pDatabaseName)
        {
            mDefaultDB = pDatabaseName;
        }
        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <param name="pChangeParameterNames">If this parameter value is given as true, the name of all parameters will be changed</param>
        /// <returns></returns>
        public CCGBatchProcess(bool pChangeParameterNames)
        {
            mChangeParameterNames = pChangeParameterNames;
        }
        /// <summary>
        /// Used to create an instance
        /// </summary>
        /// <param name="pDatabaseName">Database name to be acted on. 
        /// If this parameter is not given, default database is used. 
        /// Default database name is written in config file as the name of "DefaultDBName</param>
        /// <param name="pChangeParameterNames">If this parameter value is given as true, the name of all parameters will be changed</param>
        /// <returns></returns>
        public CCGBatchProcess(string pDatabaseName, bool pChangeParameterNames)
        {
            mDefaultDB = pDatabaseName;
            mChangeParameterNames = pChangeParameterNames;
        }

        #endregion

        #region [MEMBERS & PROPERTIES] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        private string mDefaultDB = string.Empty;
        /// <summary>
        /// Default Database name to be acted on. 
        /// If this parameter is not given, default database is used. 
        /// Default database name is written in config file as the name of "DefaultDBName"
        /// </summary>
        protected string DefaultDB
        {
            get { return mDefaultDB == string.Empty ? "DefaultDBName".ReadAppSetting<string>() : mDefaultDB; }
            set { mDefaultDB = value; }
        }

        private bool mChangeParameterNames = true;
        /// <summary>
        /// If this parameter value is given as true, the name of all parameters will be changed
        /// </summary>
        public bool ChangeParameterNames
        {
            get { return mChangeParameterNames; }
            set { mChangeParameterNames = value; }
        }

        #endregion

        #region [PROCEED] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        /// <summary>
        /// Used to run more then one command object at a time. Returns number of effected rows.
        /// </summary>
        /// <param name="pDbCommand">DbCommand object list to be acted on</param>
        /// <returns>Returns number of effected rows</returns>
        public int Proceed(List<DbCommand> pDbCommand)
        {
            return Proceed(pDbCommand, false);
        }

        /// <summary>
        /// Used to run more then one command object at a time. Returns number of effected rows.
        /// </summary>
        /// <param name="pDbCommand">DbCommand object list to be acted on</param>
        /// <param name="pIsTransactional">If true, process is transactional</param>
        public int Proceed(List<DbCommand> pDbCommand, bool pIsTransactional)
        {
            DbCommand oCmd = DataObjectAdapter.GetCommand();
            PrepareCommandObject(pDbCommand, pIsTransactional, oCmd);

            CCGDataObject dto = new CCGDataObject(mDefaultDB);
            int rowsAffected = dto.ExecuteNonQueryStatement(oCmd);
            return rowsAffected;
        }

        /// <summary>
        /// Used to run more then one command object at a time.
        /// Method fills DataTable object. If at least one of command object has select function then this method should be used.
        /// </summary>
        /// <param name="pDbCommand">DbCommand object list to be acted on</param>
        /// <param name="pIsTransactional">If true, process is transactional</param>
        /// <param name="pDt">DataTable object to be filled</param>
        public void Proceed(List<DbCommand> pDbCommand, bool pIsTransactional, DataTable pDt)
        {
            DbCommand oCmd = DataObjectAdapter.GetCommand();
            PrepareCommandObject(pDbCommand, pIsTransactional, oCmd);

            CCGDataObject dto = new CCGDataObject(mDefaultDB);
            dto.GetRecords(pDt, oCmd);
        }

        /// <summary>
        /// Used to run more then one command object at a time.
        /// Method fills object. If at least one of command object returns a scaler value then this method should be used.
        /// </summary>
        /// <param name="pDbCommand">DbCommand object list to be acted on</param>
        /// <param name="pIsTransactional">If true, process is transactional</param>
        /// <param name="pObj">Parameter object to be filled</param>
        public void Proceed(List<DbCommand> pDbCommand, bool pIsTransactional, object pObj)
        {
            DbCommand oCmd = DataObjectAdapter.GetCommand();
            PrepareCommandObject(pDbCommand, pIsTransactional, oCmd);

            CCGDataObject dto = new CCGDataObject(mDefaultDB);
            pObj = dto.ExecuteScalarStatement(oCmd);
        }

        /// <summary>
        /// ADO transaction içindeki bir SqlCommand obje listesini çalıştırmak amacı ile kullanılır
        /// Used to run more then one command object at a time by using ADO transaction.
        /// </summary>
        /// <param name="pDbCommand">DbCommand object list to be acted on</param>
        /// <param name="pDto">Transaction object in use</param>
        /// <returns></returns>
        public int Proceed(List<DbCommand> pDbCommand, CCGDataObjectAdoTran pDto)
        {
            DbCommand oCmd = DataObjectAdapter.GetCommand();
            PrepareCommandObject(pDbCommand, false, oCmd);
            oCmd.RemoveWriteLogTranSentences();

            int rowsAffected = pDto.ExecuteNonQueryStatement(oCmd);
            return rowsAffected;
        }

        #endregion

        #region [HELPER METHODS] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        private void PrepareCommandObject(List<DbCommand> pDbCommand, bool pIsTransactional, DbCommand pCmd)
        {
            //Parametrelerin isimlerine index ekle
            for (int i = 0; i < pDbCommand.Count; i++)
            {
                AdjustParameterNames(pDbCommand[i], i);
            }

            //CommandText'leri birleştir
            StringBuilder sql = new StringBuilder();
            foreach (DbCommand cmd in pDbCommand)
            {
                sql.Append(";" + cmd.CommandText);
            }

            pCmd.CommandText = sql.ToString().TrimStart(';');

            //Her bir Command objesine ait parametreleri pCmd objesine aktar
            foreach (DbCommand cmd in pDbCommand)
            {
                DbParameter[] sqlPrmArr = new DbParameter[cmd.Parameters.Count];
                cmd.Parameters.CopyTo(sqlPrmArr, 0);
                cmd.Parameters.Clear();

                pCmd.Parameters.AddRange(sqlPrmArr);
            }

            if (pCmd.Parameters.Count >= 2100) throw new ApplicationException("Parametre sayısı belirlenen sınırı aştı ! <br /><br />Bu durumun olası nedeni, çok fazla kayıt üzerinde işlem yapılmak istenmesi olabilir. <br /><br />Lütfen kayıt sayısını azaltarak tekrar deneyiniz.");

            if (pIsTransactional) pCmd.AddTransaction();
        }

        private void AdjustParameterNames(DbCommand pCmd, int pIndex)
        {
            if (!ChangeParameterNames) return;
            string cmdText = pCmd.CommandText;

            for (int i = 0; i < pCmd.Parameters.Count; i++)
            {
                cmdText = cmdText.ReplaceWholeWord(pCmd.Parameters[i].ParameterName, pCmd.Parameters[i].ParameterName + pIndex.ToString());
                pCmd.Parameters[i].ParameterName = pCmd.Parameters[i].ParameterName + pIndex.ToString();
            }
            pCmd.CommandText = cmdText;
        }

        #endregion
    }
}
